﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WPFSample.ChooseFontSample
{
    class Lister : ContentControl
    {
        ScrollViewer scroll;
        StackPanel stack;
        ArrayList list = new ArrayList();
        int indexSelected = -1;

        public event EventHandler SelectionChanged;

        public Lister()
        {
            this.Focusable = false;

            Border bord = new Border()
            {
                BorderThickness = new System.Windows.Thickness(1),
                BorderBrush = SystemColors.ActiveBorderBrush,
                Background = SystemColors.WindowBrush
            };
            this.Content = bord;

            this.scroll = new ScrollViewer()
            {
                Focusable = false,
                Padding = new Thickness(2, 0, 0, 0)
            };
            bord.Child = this.scroll;

            this.stack = new StackPanel();
            this.scroll.Content = this.stack;

            this.AddHandler(TextBlock.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.TextBlockOnMouseLeftButtonDown));
            this.Loaded += this.Lister_Loaded;
        }

        private void Lister_Loaded(object sender, RoutedEventArgs e)
        {
            this.ScrollIntoView();
        }

        public void Add(object obj)
        {
            this.list.Add(obj);
            TextBlock txtblk = new TextBlock();
            txtblk.Text = obj.ToString();
            this.stack.Children.Add(txtblk);
        }

        public void Insert(int index, object obj)
        {
            this.list.Insert(index, obj);
            TextBlock txtblk = new TextBlock();
            txtblk.Text = obj.ToString();
            this.stack.Children.Insert(index, txtblk);
        }

        public void Clear()
        {
            this.SelectedIndex = -1;
            this.stack.Children.Clear();
            this.list.Clear();
        }

        public bool Contains(object obj)
        {
            return this.list.Contains(obj);
        }

        public int Count
        {
            get
            {
                return this.list.Count;
            }
        }

        public void GoToLetter(char ch)
        {
            int offset = this.SelectedIndex + 1;
            for (int i = 0; i < this.Count; i++)
            {
                int index = (i + offset) % this.Count;
                if (char.ToUpper(ch) == char.ToUpper(this.list[index].ToString()[0]))
                {
                    this.SelectedIndex = index;
                    break;
                }
            }
        }

        public int SelectedIndex
        {
            set
            {
                if (value < -1 || value >= this.Count)
                {
                    throw new ArgumentOutOfRangeException("SelectedIndex");
                }

                if (this.indexSelected != -1)
                {
                    TextBlock txtblk = this.stack.Children[this.indexSelected] as TextBlock;
                    txtblk.Background = SystemColors.WindowBrush;
                    txtblk.Foreground = SystemColors.WindowTextBrush;
                }

                this.indexSelected = value;
                if (this.indexSelected > -1)
                {
                    TextBlock txtblk = this.stack.Children[this.indexSelected] as TextBlock;
                    txtblk.Background = SystemColors.HighlightBrush;
                    txtblk.Foreground = SystemColors.HighlightTextBrush;
                }

                this.ScrollIntoView();

                this.OnSelectionChanged(EventArgs.Empty);
            }

            get
            {
                return this.indexSelected;
            }
        }

        public object SelectedItem
        {
            set
            {
                this.SelectedIndex = this.list.IndexOf(value);
            }

            get
            {
                if (this.SelectedIndex > -1)
                {
                    return this.list[this.SelectedIndex];
                }

                return null;
            }
        }

        public void PageUp()
        {
            if (this.SelectedIndex == -1 || this.Count == 0)
            {
                return;
            }

            int index = this.SelectedIndex - (int)(this.Count * this.scroll.ViewportHeight / this.scroll.ExtentHeight);
            if (index < 0)
            {
                index = 0;
            }

            this.SelectedIndex = index;
        }

        public void PageDown()
        {
            if (this.SelectedIndex == -1 || this.Count == 0)
            {
                return;
            }

            int index = this.SelectedIndex + (int)(this.Count * this.scroll.ViewportHeight / this.scroll.ExtentHeight);
            if (index > this.Count - 1)
            {
                index = this.Count - 1;
            }

            this.SelectedIndex = index;
        }

        private void OnSelectionChanged(EventArgs empty)
        {
            if (this.SelectionChanged != null)
            {
                this.SelectionChanged(this, empty);
            }
        }

        private void ScrollIntoView()
        {
            if (this.Count == 0 || this.SelectedIndex == -1 || this.scroll.ViewportHeight > this.scroll.ExtentHeight)
            {
                return;
            }

            double heightPerItem = this.scroll.ExtentHeight / this.Count;
            double offsetItemTop = this.SelectedIndex * heightPerItem;
            double offsetItemBot = (this.SelectedIndex + 1) * heightPerItem;
            if (offsetItemTop < this.scroll.VerticalOffset)
            {
                this.scroll.ScrollToVerticalOffset(offsetItemTop);
            }
            else if (offsetItemBot > this.scroll.VerticalOffset + this.scroll.ViewportHeight)
            {
                this.scroll.ScrollToVerticalOffset(this.scroll.VerticalOffset + offsetItemBot - this.scroll.VerticalOffset - this.scroll.ViewportHeight);
            }
        }

        private void TextBlockOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.Source is TextBlock)
            {
                this.SelectedIndex = this.stack.Children.IndexOf(e.Source as TextBlock);
            }
        }
    }
}
